// ---------------------------------------------------------------------------
// © 2023 Renesas Electronics
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
// ---------------------------------------------------------------------------

// This file was autogenerated with MacrocellMode tool in ForgeFPGA Workshop.


(* top *) module macrocellmode_autogen (
  (* iopad_external_pin, clkbuf_inhibit *) input clock,

  (* iopad_external_pin *) input rst,

  (* iopad_external_pin *) output out,
  (* iopad_external_pin *) output out_en,
  (* iopad_external_pin *) output clk_en
);


  wire wire92;
  wire wire93;
  wire wire94;
  wire wire95;

  assign out_en =1'b1;
  assign clk_en =1'b1;
  assign wire94 = 1'b1;
  assign wire93 = clock;
  assign wire95 = rst;
  assign out = wire92;


  wire mcmw_breathingcontroller77_o_out_out;
  mcm_breathing_ctrl breathingcontroller77(.i_clk(wire93), .i_rst(wire95), .i_en(wire94), .o_out(mcmw_breathingcontroller77_o_out_out));
  assign wire92 = mcmw_breathingcontroller77_o_out_out;

endmodule

module mcm_breathing_ctrl #(
  parameter IN_CLK_HZ   = 50_000_000,   // It’s the input frequency value, define in Hz (Type - Decimal, Default value = 50_000_000, Min value = 1_000_000, Max value = 60_000_000)
  parameter DEPTH       = 8,            // It’s the depth value of the output PWM counter, define in bits (Type - Decimal, Default value = 8, Min value = 2, Max value = 16)
  parameter PWM_FREQ_HZ = 100,          // It’s the output PWM frequency value, define in Hz (Type - Decimal, Default value = 100, Min value = 2, Max value = 100_000)
  parameter RAMP_MULT   = 2             // It’s the value of the ramp multiplier counter, define in decimal value (Type - Decimal, Default value = 2, Min value = 1, Max value = 256)
) (
  input i_clk,     // input clock signal
  input i_rst,     // input reset signal
  input i_en,      // input enable signal
  output reg o_out // output PWM signal
);

  localparam CNT_SLOW = IN_CLK_HZ / PWM_FREQ_HZ / (2**DEPTH);
  localparam CNT_SLOW_WIDTH = $clog2(CNT_SLOW);
  localparam CNT_RAMP_WIDTH = $clog2(RAMP_MULT);

  reg                      r_clk_en   = 1'b0;
  reg [CNT_SLOW_WIDTH-1:0] r_cnt_slow = 'h0;
  reg [DEPTH-1:0]          r_cnt_pwm  = 'h0;
  reg [DEPTH-1:0]          r_cnt_duty = 'h0;
  reg [CNT_RAMP_WIDTH:0]   r_cnt_ramp = 'h0;
  reg                      r_dir      = 1'b0;

  // register enable count and main breathing counter
  always @(posedge i_clk) begin
    if (i_rst) begin
      r_cnt_slow <= 'h0;
      r_clk_en   <= 1'b0;
    end else begin
      if (i_en) begin
        r_clk_en <= 1'b0;
        if (r_cnt_slow < CNT_SLOW) begin
          r_cnt_slow <= r_cnt_slow + 1;
        end else begin
          r_cnt_slow <= 'h0;
          r_clk_en   <= 1'b1;
        end
      end
    end
  end

  // direction and ramp counters
  always @(posedge i_clk) begin
    if (i_rst) begin
      r_cnt_pwm  <= 'h0;
      r_cnt_ramp <= 'h0;
      r_cnt_duty <= 'h0;
      r_dir      <= 1'b0;
    end else begin
      if (i_en) begin
        if (r_clk_en) begin
          r_cnt_pwm <= r_cnt_pwm + 1;
          if (&r_cnt_pwm) begin
            r_cnt_pwm  <= 'h0;
            r_cnt_ramp <= r_cnt_ramp + 1;
            if (r_cnt_ramp >= (RAMP_MULT-1)) begin
              r_cnt_ramp <= 'h0;
              r_cnt_duty <= r_cnt_duty + 1;
              if (&r_cnt_duty) begin
                r_cnt_duty <= 'h0;
                r_dir      <= ~r_dir;
              end
            end
          end
        end
      end
    end
  end

  // output PWM signal
  always @(posedge i_clk) begin
    if (i_rst) begin
      o_out <= 1'b0;
    end else begin
      if (i_en) begin
        o_out <= (r_dir == 0) ? ((r_cnt_pwm < r_cnt_duty) ? 1:0) : ((r_cnt_pwm < r_cnt_duty) ? 0:1);
      end else begin
        o_out <= 1'b0;
      end
    end
  end

endmodule

